/*
 * Copyright (c) 2010-2011, okazoh_tk. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  - Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "alkes/effector/ImageEffector.h"

namespace alkes {


#define B1(i)   (uint8_t)((0xff*(i))/1)
#define B2(i)   (uint8_t)((0xff*(i))/3)
#define B3(i)   (uint8_t)((0xff*(i))/7)
#define B4(i)   (uint8_t)((0xff*(i))/15)
#define B5(i)   (uint8_t)((0xff*(i))/31)
#define B6(i)   (uint8_t)((0xff*(i))/63)

const uint8_t ImageEffector::CONVERT_TABLE1[1<<1] = {
    B1(0), B1(1),
};

const uint8_t ImageEffector::CONVERT_TABLE2[1<<2] = {
    B2(0), B2(1), B2(2), B2(3),
};

const uint8_t ImageEffector::CONVERT_TABLE3[1<<3] = {
    B3(0), B3(1), B3(2), B3(3), B3(4), B3(5), B3(6), B3(7),
};

const uint8_t ImageEffector::CONVERT_TABLE4[1<<4] = {
    B4( 0), B4( 1), B4( 2), B4( 3), B4( 4), B4( 5), B4( 6), B4( 7),
    B4( 8), B4( 9), B4(10), B4(11), B4(12), B4(13), B4(14), B4(15),
};

const uint8_t ImageEffector::CONVERT_TABLE5[1<<5] = {
    B5( 0), B5( 1), B5( 2), B5( 3), B5( 4), B5( 5), B5( 6), B5( 7),
    B5( 8), B5( 9), B5(10), B5(11), B5(12), B5(13), B5(14), B5(15),
    B5(16), B5(17), B5(18), B5(19), B5(20), B5(21), B5(22), B5(23),
    B5(24), B5(25), B5(26), B5(27), B5(28), B5(29), B5(30), B5(31),
};

const uint8_t ImageEffector::CONVERT_TABLE6[1<<6] = {
    B6( 0),  B6( 1),  B6( 2),  B6( 3),  B6( 4),  B6( 5),  B6( 6),  B6( 7),
    B6( 8),  B6( 9),  B6(10),  B6(11),  B6(12),  B6(13),  B6(14),  B6(15),
    B6(16),  B6(17),  B6(18),  B6(19),  B6(20),  B6(21),  B6(22),  B6(23),
    B6(24),  B6(25),  B6(26),  B6(27),  B6(28),  B6(29),  B6(30),  B6(31),
    B6(32),  B6(33),  B6(34),  B6(35),  B6(36),  B6(37),  B6(38),  B6(39),
    B6(40),  B6(41),  B6(42),  B6(43),  B6(44),  B6(45),  B6(46),  B6(47),
    B6(48),  B6(49),  B6(50),  B6(51),  B6(52),  B6(53),  B6(54),  B6(55),
    B6(56),  B6(57),  B6(58),  B6(59),  B6(60),  B6(61),  B6(62),  B6(63),
};

const uint8_t* ImageEffector::CONVERT_TABLE[6] = {
    CONVERT_TABLE1,
    CONVERT_TABLE2,
    CONVERT_TABLE3,
    CONVERT_TABLE4,
    CONVERT_TABLE5,
    CONVERT_TABLE6,
};

static const ComponentInfo CI_8_8_8_8[4]    = { {24,  8}, {16,  8}, { 8,  8}, { 0,  8} };
static const ComponentInfo CI_2_10_10_10[4] = { {30,  2}, {20, 10}, {10, 10}, { 0, 10} };
static const ComponentInfo CI_10_10_10_2[4] = { {22, 10}, {12, 10}, { 2, 20}, { 0,  2} };

static const ComponentInfo CI_4_4_4_4[4]    = { {12,  4}, { 8,  4}, { 4,  4}, { 0,  4} };
static const ComponentInfo CI_1_5_5_5[4]    = { {15,  1}, {10,  5}, { 5,  5}, { 0,  5} };
static const ComponentInfo CI_5_5_5_1[4]    = { {11,  5}, { 6,  5}, { 1,  5}, { 0,  1} };
static const ComponentInfo CI_8_3_3_2[4]    = { { 8,  8}, { 5,  3}, { 2,  3}, { 0,  2} };

static const ComponentInfo CI_8_8_8[3]      = { {16, 8}, { 8, 8}, { 0, 8} };
static const ComponentInfo CI_5_6_5[3]      = { {11, 5}, { 5, 6}, { 0, 5} };
static const ComponentInfo CI_3_3_2[3]      = { { 5, 3}, { 2, 3}, { 0, 2} };

static const ComponentInfo CI_8[1]          = { { 0, 8} };

static const ComponentInfo CI_0[1]          = { { 0, 0} };


ImageEffector::ImageEffector(ImageBufferFactory* factory)
: factory_(factory)
{
}

ImageEffector::~ImageEffector()
{
}

ImageBuffer* ImageEffector::createImageBuffer(uint16_t width, uint16_t height, PixelFormat format, bool write_only)
{
    return factory_->createImageBuffer(width, height, format, write_only);
}

ImageBuffer* ImageEffector::cloneImageBuffer(ImageBuffer* src)
{
    return factory_->cloneImageBuffer(src);
}

ImageBuffer* ImageEffector::cloneImageBuffer(ImageBuffer* src, const Rect& rect)
{
    return factory_->cloneImageBuffer(src, rect);
}

int ImageEffector::getComponentInfo(PixelFormat format, const ComponentInfo* components[4])
{
    const PixelFormatTraits* traits = alkes_get_pixel_format_traits(format);

    int i;
    for (i = 0; i < traits->component_num; ++i)
    {
        components[i] = &traits->components[i];
    }

    return traits->component_num;
}

int ImageEffector::getComponentInfo(ImageBuffer* image, const ComponentInfo* components[4])
{
    return getComponentInfo(image->getPixelFormat(), components);
}

}
